<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>5.8.1.1-了解关于使用 Proxy 代理 Set 或Map 类型数据的注意事项。</title>
</head>

<body>
    <div id="container"></div>
</body>
    <script>
    /**
     * p.size 属性获取元素的数量
     * -得到了一个错误。
     *   错误信息的大意是“在不兼容的 receiver 上调用了 get Set.prototype.size 方法”
     * 
     * Set.prototype.size 是一个访问器属性。
     * - 通过代理对象 p 来访问 size 属性的，所以 this 就是代理对象 p
     * - 调用抽象方法 RequireInternalSlot(S, [[SetData]]) 来检查 S 是否存在内部槽 [[SetData]]。
     * - 代理对象 S 不存在 [[SetData]] 这个内部槽，
     *    于是会抛出一个错误，也就是前面例子中得到的错误。
     * 
     * 修复这个问题
     * - 需要修正访问器属性的 getter 函数执行时的 this 指向
     * - 检查读取的属性名称是不是 size，如果是，
     *    则在调用 Reflect.get 函数时指定第三个参数为原始 Set 对象，
     *    这样访问器属性 size 的 getter 函数在执行时，
     *    其 this 指向的就是原始 Set 对象而非代理对象了
     */

    const s = new Set([1, 2, 3])
    const p = new Proxy(s, {
        get(target, key, receiver) {
            if (key === 'size') {
                // 如果读取的是 size 属性
                // 通过指定第三个参数 receiver 为原始对象 target 从而修复问题
                return Reflect.get(target, key, target)
            }
            // 读取其他属性的默认行为
            return Reflect.get(target, key, receiver)
        }
    })

    console.log(p.size) // 报错 TypeError: Method get Set.prototype.size called on incompatible receiver

</script>

</html>